﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Be.Windows.Forms;
using Pahan.McuFusion.Common;
using Pahan.McuFusion.UI.Interfaces;
using Pahan.McuFusion.UI.Properties;

namespace Pahan.McuFusion.UI.Views
{
    public partial class MemoryView : UserControl, IMemoryView
    {
        private MemoryView()
        {
            InitializeComponent();
            statusStrip.Renderer = new RibbonStatusStripRenderer();
        }

        public MemoryView(MemoryClassInfo memory) : this()
        {
            Assert.NotNull(memory, "memory");
            tsslInsertActive.Text = hexBox.InsertActive ? "INS" : "OVR";
            MemoryClass = memory;
            CreateRibbonTab();
            Data = new byte[0];
        }

        #region Implementation of IMemoryView

        /// <summary>
        /// Gets or sets the data.
        /// </summary>
        public IList<byte> Data
        {
            get
            {
                return dataProvider != null ?
                    dataProvider.Bytes :
                    new byte[0];
            }
            set
            {
                if (hexBox.ByteProvider != null)
                {
                    hexBox.ByteProvider.LengthChanged -= ByteProvider_LengthChanged;
                    hexBox.ByteProvider = null;
                    GC.Collect();
                }
                if (value != null)
                {
                    dataProvider = new DynamicListByteProvider(value);
                    hexBox.ByteProvider = dataProvider;
                    hexBox.ByteProvider.LengthChanged += ByteProvider_LengthChanged;
                    tsslLengthValue.Text = value.Count.ToString();
                    rbtnProgram.Enabled = value.Count > 0;
                    GC.Collect();
                }
            }
        }

        /// <summary>
        /// Gets the memory class info.
        /// </summary>
        public MemoryClassInfo MemoryClass
        {
            get;
            private set;
        }

        /// <summary>
        /// Get a value indicating whether the user can open a file.
        /// </summary>
        public bool CanOpen
        {
            get { return true; }
        }

        /// <summary>
        /// Get a value indicating whether the user can save the file.
        /// </summary>
        public bool CanSave
        {
            get { return true; }
        }

        /// <summary>
        /// Gets the ribbon tab associated with the view.
        /// </summary>
        public object GetRibbonTab()
        {
            return ribbonTab;
        }

        public event EventHandler ProgramRequested;

        public event EventHandler ReadRequested;

        public event EventHandler EraseRequsted;
       
        public event EventHandler OpenFileRequested;
        
        public event EventHandler SaveFileAsRequested;

        #endregion

        #region Ribbon

        public void CreateRibbonTab()
        {
            ribbonTab = new RibbonTab();
            ribbonTab.Text = MemoryClass.Name;
            ribbonTab.Tag = this;

            CreateRomFilePanel();
            CreateProgrammingPanel();
            CreateViewPanel();

            ribbonTab.Panels.Add(rpRomFile);
            ribbonTab.Panels.Add(rpProgramming);
            ribbonTab.Panels.Add(rpView);
        }

        private void CreateRomFilePanel()
        {
            //rbtnNew = new RibbonButton("New")
            //{
            //    Image = Resources.NewLarge,
            //    SmallImage = Resources.New
            //};

            rbtnOpen = new RibbonButton("Open")
            {
                Image = Resources.OpenLarge,
                SmallImage = Resources.Open
            };
            rbtnOpen.Click += rbtnOpen_Click;

            rbtnSaveAs = new RibbonButton("Save As")
            {
                Image = Resources.SaveAsLarge,
                SmallImage = Resources.Save
            };
            rbtnSaveAs.Click += rbtnSaveAs_Click;

            rpRomFile = new RibbonPanel(
                "ROM File",
                RibbonPanelFlowDirection.Bottom,
                new[] { /*rbtnNew,*/ rbtnOpen, rbtnSaveAs })
            {
                ButtonMoreVisible = false
            };
        }

        private void CreateProgrammingPanel()
        {
            rbtnProgram = new RibbonButton("Program")
            {
                Enabled = (Data.Count > 0) && MemoryClass.CanWrite,
                Image = Resources.ProgramLarge,
                SmallImage = Resources.Program
            };
            rbtnProgram.Click += rbtnProgram_Click;

            rbtnRead = new RibbonButton("Read")
            {
                Enabled = MemoryClass.CanRead,
                Image = Resources.ReadLarge,
                SmallImage = Resources.Read
            };
            rbtnRead.Click += rbtnRead_Click;

            rbtnErase = new RibbonButton("Erase")
            {
                Enabled = MemoryClass.CanRead,
                Image = Resources.EraseLarge,
                SmallImage = Resources.Erase
            };
            rbtnErase.Click += rbtnErase_Click;

            rpProgramming = new RibbonPanel(
                "Programming",
                RibbonPanelFlowDirection.Bottom,
                new[] { rbtnProgram, rbtnRead, rbtnErase })
            {
                ButtonMoreVisible = false
            };
        }

        private void CreateViewPanel()
        {
            rbtnAuto = new RibbonButton("Bytes per Line: Auto")
            {
                Checked = true,
                MaxSizeMode = RibbonElementSizeMode.Compact,
                SmallImage = Resources.BytesAuto,
                Tag = 0
            };
            rbtnAuto.Click += rbtnBytesPerLine_Click;

            rbtnBytes8 = new RibbonButton("Bytes per Line: 8")
            {
                MaxSizeMode = RibbonElementSizeMode.Compact,
                SmallImage = Resources.Bytes8,
                Tag = 8
            };
            rbtnBytes8.Click += rbtnBytesPerLine_Click;

            rbtnBytes16 = new RibbonButton("Bytes per Line: 16")
            {
                MaxSizeMode = RibbonElementSizeMode.Compact,
                SmallImage = Resources.Bytes16,
                Tag = 16
            };
            rbtnBytes16.Click += rbtnBytesPerLine_Click;

            rbtnBytes24 = new RibbonButton("Bytes per Line: 24")
            {
                MaxSizeMode = RibbonElementSizeMode.Compact,
                SmallImage = Resources.Bytes24,
                Tag = 24
            };
            rbtnBytes24.Click += rbtnBytesPerLine_Click;
            
            rbtnBytes32 = new RibbonButton("Bytes per Line: 32")
            {
                MaxSizeMode = RibbonElementSizeMode.Compact,
                SmallImage = Resources.Bytes32,
                Tag = 32
            };
            rbtnBytes32.Click += rbtnBytesPerLine_Click;
            
            rbtnBytes48 = new RibbonButton("Bytes per Line: 48")
            {
                MaxSizeMode = RibbonElementSizeMode.Compact,
                SmallImage = Resources.Bytes48,
                Tag = 48
            };
            rbtnBytes48.Click += rbtnBytesPerLine_Click;

            rigBytesPerLine = new RibbonItemGroup(
                new[] { rbtnAuto, rbtnBytes8, rbtnBytes16, rbtnBytes24, rbtnBytes32, rbtnBytes48});

            rbtnShowLineInfo = new RibbonButton("Show Line Numbers")
            {
                Checked = hexBox.LineInfoVisible,
                MaxSizeMode = RibbonElementSizeMode.Medium,
                MinSizeMode = RibbonElementSizeMode.Medium,
                SmallImage = Resources.ShowLines,
            };
            rbtnShowLineInfo.Click += rbtnShowLineInfo_Click;

            rbtnShowStrings = new RibbonButton("Show Strings")
            {
                Checked = hexBox.StringViewVisible,
                Enabled = !rbtnAuto.Checked,
                MaxSizeMode = RibbonElementSizeMode.Medium,
                MinSizeMode = RibbonElementSizeMode.Medium,
                SmallImage = Resources.ShowString,
            };
            rbtnShowStrings.Click += rbtnShowStrings_Click;

            rpView = new RibbonPanel("View", RibbonPanelFlowDirection.Bottom,
                new RibbonItem[] {rigBytesPerLine, rbtnShowLineInfo, rbtnShowStrings})
            {
                ButtonMoreVisible = false
            };
        }

        #region Ribbon Event Handlers

        private void rbtnOpen_Click(object sender, EventArgs e)
        {
            var handler = OpenFileRequested;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void rbtnSaveAs_Click(object sender, EventArgs e)
        {
            var handler = SaveFileAsRequested;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void rbtnProgram_Click(object sender, EventArgs e)
        {
            var handler = ProgramRequested;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void rbtnRead_Click(object sender, EventArgs e)
        {
            var handler = ReadRequested;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void rbtnErase_Click(object sender, EventArgs e)
        {
            var handler = EraseRequsted;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        private void rbtnBytesPerLine_Click(object sender, EventArgs e)
        {
            var clickedButton = (RibbonButton)sender;
            foreach (var btn in rigBytesPerLine.Items.OfType<RibbonButton>())
            {
                btn.Checked = btn == clickedButton;
            }
            int bytes = (int)clickedButton.Tag;
            if (bytes == 0)
            {
                hexBox.UseFixedBytesPerLine = false;
            }
            else
            {
                hexBox.UseFixedBytesPerLine = true;
                hexBox.BytesPerLine = bytes;
            }
            rbtnShowStrings.Enabled = clickedButton != rbtnAuto;
        }

        private void rbtnShowLineInfo_Click(object sender, EventArgs e)
        {
            hexBox.LineInfoVisible = !hexBox.LineInfoVisible;
            rbtnShowLineInfo.Checked = hexBox.LineInfoVisible;
        }

        private void rbtnShowStrings_Click(object sender, EventArgs e)
        {
            hexBox.StringViewVisible = !hexBox.StringViewVisible;
            rbtnShowStrings.Checked = hexBox.StringViewVisible;
        }

        #endregion

        #region Ribbon Items

        private RibbonTab ribbonTab;

        private RibbonPanel rpRomFile;
        private RibbonButton rbtnNew;
        private RibbonButton rbtnOpen;
        private RibbonButton rbtnSaveAs;

        private RibbonPanel rpProgramming;
        private RibbonButton rbtnProgram;
        private RibbonButton rbtnRead;
        private RibbonButton rbtnErase;

        private RibbonPanel rpView;
        private RibbonItemGroup rigBytesPerLine;
        private RibbonButton rbtnAuto;
        private RibbonButton rbtnBytes8;
        private RibbonButton rbtnBytes16;
        private RibbonButton rbtnBytes24;
        private RibbonButton rbtnBytes32;
        private RibbonButton rbtnBytes48;
        private RibbonButton rbtnShowLineInfo;
        private RibbonButton rbtnShowStrings;

        #endregion

        #endregion

        #region Private Members

        private DynamicListByteProvider dataProvider;

        #endregion

        #region Event Handlers

        private void hexBox_InsertActiveChanged(object sender, EventArgs e)
        {
            tsslInsertActive.Text = hexBox.InsertActive ? "INS" : "OVR";
        }

        private void hexBox_SelectionChanged(object sender, EventArgs e)
        {
            if (hexBox.SelectionLength == 0)
            {
                tsslOffsetValue.Text = String.Format("0x{0:X8}", hexBox.SelectionStart);
            }
            else
            {
                tsslOffsetValue.Text = String.Format("0x{0:X8}-0x{1:X8}",
                    hexBox.SelectionStart, hexBox.SelectionStart + hexBox.SelectionLength);
            }
        }

        private void ByteProvider_LengthChanged(object sender, EventArgs e)
        {
            tsslLengthValue.Text = Data.Count.ToString();
            rbtnProgram.Enabled = (Data.Count > 0) && MemoryClass.CanWrite;
        }

        private void tsslInsertActive_DoubleClick(object sender, EventArgs e)
        {
            hexBox.InsertActive = !hexBox.InsertActive;
        }

        #endregion
    }
}
